package com.gitee.pifeng.phoenix.insightor;

import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.matcher.ElementMatchers;

import java.lang.instrument.Instrumentation;

/**
 * <p>
 * 在应用程序启动前对JVM进行一些特殊的配置或修改
 * </p>
 *
 * @author 皮锋
 * @custom.date 2025/1/18 21:21
 */
@Slf4j
public class PreMain {

    /**
     * <p>
     * premain是Java中的一个特殊方法，它与Java代理（Java agent）技术紧密相关。当JVM启动时，如果指定了-javaagent参数，
     * 那么该参数指定的代理JAR文件中的premain方法会在主类的main方法之前执行。
     * </p>
     *
     * @param agentArgs 从命令行传递给代理的参数字符串。
     * @param inst      {@link Instrumentation}是Java SE 5的新特性，它把Java的instrument功能从本地代码中释放出来，
     *                  使其可以用Java代码的方式解决问题。使用{@link Instrumentation}，开发者可以构建一个独立于应用程序的代理程序，
     *                  用来监测和协助运行在JVM上的程序，甚至可以替换和修改某些类的定义。
     *                  有了这样的功能，开发者就可以实现更为灵活的虚拟机监控和Java的类操作了。
     *                  这样的特性实际上提供了一种JVM级别支持的AOP方式，使得开发者无需对原有应用做任何修改，就可以实现类的动态修改和增强。
     * @author 皮锋
     * @custom.date 2025/1/18 22:00
     */
    public static void premain(String agentArgs, Instrumentation inst) {
        try {
           /* new AgentBuilder.Default()
                    // 告诉Byte Buddy尝试使用重新转换来应用字节码修改，通过启用重新转换，可以确保即使是那些在代理安装之前就已经被加载的类也能被正确拦截和修改
                    .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
                    // 指定要匹配的类类型
                    .type(ElementMatchers.is(ThreadPoolExecutor.class).or(ElementMatchers.isSubTypeOf(ThreadPoolExecutor.class)))
                    // 定义如何转换匹配到的类
                    // builder: 用于进一步构建类的 ByteBuddy 实例
                    // typeDescription: 匹配到的类的描述信息
                    // classLoader: 加载该类的类加载器
                    // module: 类所属的模块（适用于 Java 9 及以上版本）
                    .transform((builder, typeDescription, classLoader, module) ->
                            // 所有构造方法
                            builder.constructor(ElementMatchers.any())
                                    // 定义拦截后要执行的操作
                                    .intercept(Advice.to(ThreadPoolMonitorAdvice.class)))
                    // 安装代理
                    .installOn(inst);*/
            new AgentBuilder.Default()
                    .type(ElementMatchers.nameStartsWith("java.util.concurrent"))
                    .transform((builder, typeDescription, classLoader, module) ->
                            builder.visit(Advice.to(MethodInterceptor.class).on(ElementMatchers.any()))
                    ).installOn(inst);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    public static class MethodInterceptor {
        @Advice.OnMethodEnter
        public static void enter(@Advice.Origin String method) {
            System.out.println("Entering method: " + method);
        }
    }

}
